home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 13163 < prev    next >
Encoding:
Text File  |  1996-08-05  |  4.9 KB  |  128 lines

  1. Path: news.compuserve.com!newsmaster
  2. From: Philippe Verdy <100105.3120@compuserve.com>
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: What's mean about '...'
  5. Date: 24 Mar 1996 00:27:40 GMT
  6. Organization: CompuServe Incorporated
  7. Message-ID: <4j24ts$shm@arl-news-svc-3.compuserve.com>
  8. NNTP-Posting-Host: ad53-232.compuserve.com
  9.  
  10. cywong@asiaonline.net (Wong Chi Yat) s'Θcrit :
  11. > Could you tell me what's mean about "..." which is defined in C language
  12. > procedure, e.g. void test(char *t, ...)
  13. > I wish you could tell me how to implement? 
  14. > Thank you very much?
  15. > e-mail: cywong@asiaonline.net
  16. > A
  17. "..." is a placeholder for unknown parameters, so it is not
  18. conforming to the C++ strict-typing philosophy. As far as I
  19. know, the only places where it appears in the C library is for
  20. XXXprintf() and XXXscanf() functions. These functions are
  21. dangerous in C and also in C++, because there is no type-checking
  22. and all is done by interpreting their first (char*format)
  23. argument. If the string is invalid, segment violation will
  24. occur. Also, there is no way to limit very safely the limit
  25. of data written or read from those functions. That's why
  26. C++ streams have been created, and no C++ RTL/STL functions
  27. use them.
  28.  
  29. However they are still permitted. Use them like this:
  30.  
  31. #include <stdarg.h> // ANSI-C/C++ support for varying arguments
  32. // ...
  33. int logprintf(char *format, ...)
  34. {
  35.   char buffer[1024];
  36.   va_list args;
  37.  
  38.   va_start(args, format);
  39.   vsprintf(buffer, format, args);
  40.   va_end(args);
  41.   clog << buffer;
  42. }
  43.  
  44. va_start initialise an argument pointer pointing to the unknown
  45. arguments of the function. This pointer is useable as is for
  46. calling vXXXprintf() or vXXXscanf() functions (which have 
  47. fixed arguments, and are type-safe on these arguments only).
  48.  
  49. va_end is required once we have ended using the varying
  50. arguments list. On most platforms it does not make anything
  51. but it is not always true (va_start may on some platforms
  52. build-up a stack segment to access those parameters which
  53. otherwise would only be accessible thru processor registers,
  54. forgetting to use va_end could produce memory leaks or could
  55. crash the function when it exits !)
  56.  
  57. You can parse each varying argument, provided you have a
  58. model of how they are disposed. On XXXprintf and XXXscanf
  59. functions, the model is the format string which is scanned
  60. in order to find out what kind or arguments are expected.
  61. Parsing these arguments will always be done from left to
  62. right, taking one parameter at a time. To rescan the parameters
  63. you must first use va_end(args), then recall va_start(args).
  64. The arguments pointer (args) is always of type (va_list)
  65.  
  66. To get the next varying argument of type T, use: 
  67.     va_list args;
  68.     T      vararg1; // variables to store values of
  69.     char * vararg2; // varying arguments
  70.     
  71.     va_start(args, lastfixed);  // init
  72.     ...
  73.     vararg1 = va_arg(args, T);      // use it repeatedly
  74.     vararg2 = va_arg(args, char *); // use it repeatedly
  75.     ...
  76.     va_end(args);               // end
  77. this will get the value of that argument, and advance the args
  78. pointer to next argument. Varying arguments can have any type
  79. valid in C.
  80.  
  81. Do not compute the new value of args yourself: the size of T
  82. is not always the size by which the argument pointer is moved
  83. forward, and sometimes this pointer is incremented or
  84. decremented (depending on the platform stack implementation).
  85.  
  86. So not assume also that args is directly pointing to the argu
  87. ment itself: it could point on another place, depending on the
  88. type of the argument, or it could be an internal argument
  89. index, used in functions called by the va_arg() macro !
  90.  
  91. Do not use va_arg() to get other arguments than those which
  92. are specified as unknown : depending on the architecture, the
  93. compiler could generate different memory models for fixed and
  94. varying arguments ! The argument name you give to va_start
  95. is the last fixed argument before the "..." specifier.
  96.  
  97. You need at least one fixed argument before the varying ones.
  98. This is a major difference with the old K&R-style <varargs.h>
  99. macros for accessing varying arguments.
  100.  
  101. As for all macros which have side effects on some variables,
  102. do not use them several times within an expression, because
  103. these macros are often complex and the order of evaluation
  104. is important and could give unexpected results. For example,
  105. do not use the following:
  106.   ...
  107.   my_func(va_arg(args, int), va_arg(args, int));
  108.   ...
  109. which is very implementation dependant, but use:
  110.   int a, b;
  111.   ...
  112.   a = va_arg(args, int);
  113.   b = va_arg(args, int);
  114.   my_func(a, b);
  115.  
  116. Under Borland-C++, the "..." specifier has also a second usage
  117. different than the place-holder for varying arguments declaration.
  118. In an expression, it evaluates directly as a va_list pointer
  119. to the first varying argument of the function. This makes the
  120. va-start() macro very simple and more secure, as you can give
  121. any argument to va_start(), not only the last fixed one.
  122. However, it can produce confusion when porting to other
  123. compilers or platforms. So refrain using it like this.
  124.